package com.sdyeda.readiot;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;
import com.fazecast.jSerialComm.SerialPort;
import com.sdyeda.readiot.api.CallApi;
import com.sdyeda.readiot.config.Setting;
import com.sdyeda.readiot.data.SetSave;
import com.sdyeda.readiot.fx.MainWindowController;
import com.sdyeda.readiot.fx.ReadDialogController;
import com.sdyeda.readiot.iotinfo.IotData;
import com.sdyeda.readiot.iotinfo.IotInfo;
import com.sdyeda.readiot.iotinfo.JdbcIotInfo;
import com.sdyeda.readiot.iotinfo.ReadingInfo;
import com.sdyeda.readiot.tools.HexTools;

//重要测试
public class ReadTaskService {

	Object lock = 0;
	
	private int retrytime = 0;

	private final Log log = LogFactory.getLog(this.getClass());

	private int numiots=0;
	private int numsuccess =0;
	
	SerialPort comPort = null;
	
	void sleep(long t) {
		try {
			Thread.sleep(t);
		} catch (InterruptedException e) {
		}
	}
	
	public void ReadComStepByStep(IotInfo iotinfo,String command,ReadDialogController controller) {
		//读写缓冲区
		//SendBuff sendBuff = new SendBuff();
		//ReceiveBuff receiveBuff = new ReceiveBuff();
		//receiveBuff.set
		
		@SuppressWarnings("unchecked")
		Map<String,SetSave> saves = (Map<String,SetSave>)Setting.Get(Setting.IOTTYPE);
		SetSave save = saves.get(iotinfo.getType());
		
		IotData iotdata = null;
		
		controller.clearInfo();
		controller.setInfo(0, "开始...", -1);
		sleep(100);
		controller.setInfo(0, "第一步：连接串口。", -1);
		sleep(300);
		
		//Step1 打开串口
		comPort = open(iotinfo.getCom());
		
		if (comPort == null) {
			//log.error(com + "打开失败！");
			controller.setInfo(0, iotinfo.getCom()+"连接失败，异常终止！", -1);
			return ;
		}
		controller.setInfo(1.0/6, iotinfo.getCom()+"连接成功。", -1);
		sleep(300);
		
		controller.setInfo(1.0/6, "第二步：初始化发送缓冲区。", -1);
		sleep(300);
		//Setp2 初始化发送缓冲区 
		byte[] sendbuff = CallApi.MakeSender(save.getJarname(),save.getClassname(), iotinfo.getIotid(), command);
		
		if(sendbuff ==null) {
			controller.setInfo(1.0/6, "发送缓冲区初始化失败！", -1);
			return ;
		}
		
		controller.setInfo(2.0/6, "发送缓冲区初始化成功。", -1);
		controller.setInfo(2.0/6, "发送缓冲区："+ HexTools.bytesToHex(sendbuff), -1);
		//sleep(300);
	
		controller.setInfo(2.0/6, "第三步：发送数据指令。", -1);
		//Step3 发送指令数据
		if (!write(sendbuff)) {
			//log.error("发送指令失败");
			controller.setInfo(2.0/6, "数据指令发送失败，异常终止！", -1);
			close();
			return ;
		}
		
		controller.setInfo(3.0/6,"发送数据指令成功！",-1);
		//sleep(300);
		
		controller.setInfo(3.0/6, "第四步：读取数据。", -1);
		//Step4 读取数据
		byte[] recive = read(2000l);
		//log.info("读取数据"+n + "字节：" + receiveBuff.toString());
		if (recive==null) {
			controller.setInfo(3.0/6, "数据读取失败，异常终止！", -1);
			//log.error("读取传感器失败");
			close();
			return ;
		}
		//close(comPort);
		
		controller.setInfo(4.0/6, "读取数据成功，收到"+recive.length+"字节数据。", -1);
		controller.setInfo(4.0/6, "数据："+HexTools.bytesToHex(recive), -1);
		//sleep(300);
		
		controller.setInfo(4.0/6, "第五步：解析数据。", -1);
		//Step5 解析数据
		String jsonData = CallApi.DecRecive(save.getJarname(), save.getClassname(), recive);
		if (jsonData == null) {
			
			controller.setInfo(4.0/6, "数据解析失败，异常终止！", -1);
			//log.error("解析传感器数据失败");
			close();
			return ;
		} else {
			iotdata = JSON.parseObject(jsonData, IotData.class);
			if (iotdata == null) {
				controller.setInfo(4.0 / 6, "数据解析失败，异常终止！", -1);
				close();
				return;
			}
		}
		controller.setInfo(5.0/6, "解析数据成功。", -1);
		if(command != "read") {	//调零不输出
			controller.setInfo(5.0/6, "数据："+jsonData, -1);
		}
		sleep(500);
		/*
		controller.setInfo(0, "第六步：存储数据。", -1);
		//Step6 存储数据
		
		int ret = 0;
		try { 
			ret = JdbcIotInfo.write(receiveBuff.getIotdata());
		}
		catch(Exception e) {
		}
		if(ret <=0) {
			controller.setInfo(0, "数据存储失败，异常终止！", -1);
		}
		controller.setInfo(0, "数据存储成功。", -1);
		//sleep(500);
		*/
		controller.setInfo(5.0/6, "第六步：关闭串口。", -1);
		close();
		sleep(300);
		controller.setInfo(6.0/6, "关闭串口成功。", -1);
		controller.setInfo(1, "结束。", -1);
	}
	
	public Integer ReadCom(String com, List<IotInfo> listIotinfo) {

		//读取重试次数
		retrytime = (int) Setting.setting.get(Setting.RETRYTIMES);

		//设备接口程序
		@SuppressWarnings("unchecked")
		Map<String,SetSave> saves = (Map<String,SetSave>)Setting.Get(Setting.IOTTYPE);

		//传感器数
		numiots = listIotinfo.size(); 	
		numsuccess = 0;
		
		comPort = open(com);
		
		if (comPort == null) {
			log.error(com + "打开失败！");
			return 0;
		}


		listIotinfo.forEach(item -> {
			
			//获得传感器类型和接口程序名称等信息
			SetSave save = saves.get(item.getType());
			
			IotData iotdata = null;
			boolean success = false;
			
			//调用接口生成发送数组 jarname，classname与ID
			byte[] sendbuff =CallApi.MakeSender(save.getJarname(), save.getClassname(), item.getId());
			if(sendbuff!=null) {

				int i=1;
				for (i = 1; i <= retrytime; i++) {
					Long delay = 2000l + i * 3000l;

					//发送
					if (!write(sendbuff)) {
						break;
					}
					
					//读取数据
					byte[] recive = read(delay);
					if (recive == null) {
						continue;
					}
					//调用接口解析收到数组
					String jsonData = CallApi.DecRecive(save.getJarname(), save.getClassname(), recive);
					if (jsonData == null) {
						continue;
					} else {
						iotdata = JSON.parseObject(jsonData, IotData.class);
						if(iotdata ==null) {
							continue;
						}
						iotdata.setReadtimes(i);
						success = true;
						break;
					}
				}
				if (success) {
					
					log.info(com+"-- "+item.getId()+" 读取成功！");
					
					if(JdbcIotInfo.write(iotdata)>0) {
						log.info(com+"-- " +item.getId()+" 数据存储成功！");
						numsuccess +=1;
					}
					else {
						log.error(com+"--" +item.getId()+" 数据存储失败!");
					}
				} else {
					log.error(com+"-- " +item.getId()+" 读取失败！");
				}
				
			}else {
				log.error(com+"-- " +item.getId()+" 读取失败！");
			}

			synchronized (lock) {
				((ReadingInfo) Setting.Get(Setting.READINGINFO)).setIotData(iotdata);
				MainWindowController controller = (MainWindowController) Setting.Get(Setting.MAINWINDOW_CONTROLLER);
				if(controller!=null) {
					controller.refushList();
				}
			}

		});
		log.info(com+"总计"+numiots+"个传感器,成功读取"+numsuccess+"个！");
		
		close();
		return numsuccess;
	}


/*
	boolean readiot(SendBuff sendBuff, ReceiveBuff receiveBuff,int times) {

		comPort.flushIOBuffers();

		if (write(sendBuff.getBuff(), sendBuff.getSize()) < sendBuff.getSize()) {
			//log.error("发送指令失败");
			return false;
		}
		//log.info("发送数据" + sendBuff.toHexString() + "成功！");

		receiveBuff.clearbuff();

		// while(comPort.bytesAvailable>0){//循环读取所有的返回数据。如果可读取数据长度为0或-1，则停止读取
		//失败则增加读取时间
		
		if (sendBuff.getBuff()[2] == (byte) 0x1B) { // 雨量计历史数据需要增加时间
			times = times * times + 8;
		} 
		//log.info("读取数据"+n + "字节：" + receiveBuff.toString());
		//根据次数设置读取时间，第一次2秒，每次增加1秒-----------经测试，2秒时间比较合适
		Long delay = 2000l+times*2000l;
		byte[] recive = read( delay);
		if (recive==null) {
			//log.error("读取传感器失败");
			return false;
		}

		//receiveBuff.setReadnums(n);

		if (!receiveBuff.Analysis()) {
			log.error("解析传感器数据失败");
			return false;
		}

		return true;
	}
*/
	SerialPort open(String com) {
		SerialPort comPort;
		try {
			comPort = SerialPort.getCommPort(com);
			comPort.setComPortParameters(9600, 8, 1, 0);
			//comPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 50000, 1000); // 5秒

			if (comPort.openPort()) {
				// System.out.println(comPort.isOpen());
				return comPort;
			}
		} catch (Exception e) {
			// System.out.println(e);
			return null;
		}
		return null;
	}

	Boolean write(byte[] buf) {
		int writelen = 0;
		if (comPort == null) {
			return false;
		}
		try {
			writelen = comPort.writeBytes(buf, buf.length);
			Thread.sleep(100);// 休眠0.1秒，等待下位机返回数据。如果不休眠直接读取，有可能无法成功读到数据
			return writelen == buf.length;
		} catch (Exception e) {
			return false;
		}
	}

	//现场重点测试此函数
	byte[] read( Long delay) {
		int availnum = 0;	//准备好数据尺寸
		int readnum = 0;	//读取尺寸
		int sumnum = 0;		//累计读取尺寸
		byte[] readbuf = null;
		byte[] buf = new byte[1024];
		if (comPort == null) {
			return null;
		}
		try {
			//根据次数设置读取时间，第一次2秒，每次增加1秒-----------经测试，2秒时间比较合适
			long now= new Date().getTime();
			while ((new Date()).getTime() - now < delay) {//2000+1000*times) {
				availnum = comPort.bytesAvailable();
				if (availnum < 0) break;	//无数据
				if(availnum == 0) continue;//数据未准备好
				
				readbuf = new byte[availnum];
				readnum = comPort.readBytes(readbuf, availnum);
				//System.out.println("---"+readnum+"  time:"+times);
				if (readnum > 0) {
					System.arraycopy(readbuf, 0, buf, sumnum, readnum);
					sumnum += readnum;
				}
				Thread.sleep(100);
			}
			
		} catch (Exception e) {
			return null;
		}
		byte[] result = new byte[sumnum];
		System.arraycopy(buf,0,result,0,sumnum);
		return result;
	}

	void close() {
		if (comPort != null && comPort.isOpen()) {
			try {
				comPort.closePort();
			} catch (Exception e) {

			}
		}
	}
}
